package com.cskaoyan.javase.object._6clone;

/**
 * clone方法是一个非常独特的方法,因为它代表了一种完全不同于new对象的创建对象的方式,但是它并不重要,因为这种创建对象的方式几乎不使用
 * 总之,了解这个方法,知道clone方法是一种独特的创建对象的方式就可以了
 *
 * clone方法的方法声明为：
 * protected native Object clone() throws CloneNotSupportedException;
 *      1.注意访问权限protected
 *      2.其次该方法是本地方法,不需要关注它的具体实现
 *      3.该方法的返回值类型是Object,返回一个对象
 *      4.throws CloneNotSupportedException 方法抛出异常的声明列表
 *
 * 方法的作用
 * 这个方法的名字，其实已经很明显的告诉了你它的作用：
 * 克隆，生物学意义上的克隆，是用生物的体细胞，经过无性繁殖，得到相同基因型后代的过程。
 *
 * Java当中的克隆方法clone()有类似的作用，当你在程序中有这种需求，即希望：
 *      得到一个和原先对象，完全独立的新对象。
 *      成员仍和原先对象一致。
 * 有这种做法时，普通的做法就是再new一个一模一样的，
 * 但学习clone方法后，你就可以用该方法来做这个事情了。
 * 所以Object类当中的clone方法默认实现:
 *      就是得到一个独立的，和原先对象成员一致的新对象。
 *
 * clone方法的基本使用步骤:
 *      1.(必做)必须突破protected访问权限,否则就是只能自己克隆自己(一般意义不大)
 *          重写方法的访问权限
 *      2.(选做,推荐)重写返回值类型
 *          Object类当中的clone方法默认实现是一定不会改变对象类型,所以子类可以重写返回值类型
 *      3.(必做)必须让克隆对象的类实现接口java.lang.Cloneable
 *          如果某个类没有实现上述接口就执行克隆操作
 *          会抛出异常CloneNotSupportedException,并且终止程序执行
 *
 * 细节问题:
 *      1.java.lang.Cloneable是一个标记接口,实现它就表示该类对象允许做克隆操作
 *      2.clone方法是一种新的创建对象的方式，和new对象的方式是平行的关系，是独立的关系。
 *          调用clone方法得到对象的过程，是依赖于本地方法实现的，不会去调用构造器。
 *
 * @since 17:03
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student(18, 700);
        Student s2 = new Student(18, 700);
        // 需求: 在这里克隆一个s1对象
        Student cloneStu = s1.clone();
        // clone得到的是一个独立的新对象,所以"=="连接会返回false
        System.out.println(s1 == cloneStu);
        // 根据成员变量取值重写了equals,由于克隆对象和原先对象成员一致,会返回true
        System.out.println(s1.equals(cloneStu));
    }
}
// 该接口是java.lang.Cloneable接口的子接口
/*
    分析:
        之前某个类实现java.lang.Cloneable
        现在实现java.lang.Cloneable的子接口
        相当于某个类从原先java.lang.Cloneable的直接子类,变成间接子类
        但是不管直接,间接都是子类
        用instanceof判断,都可以通过
 */
interface MyCloneable extends Cloneable {
}

class Student implements MyCloneable {
    int age;
    double score;

    public Student(int age, double score) {
        System.out.println("构造器执行了!");
        this.age = age;
        this.score = score;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.score, score) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    /* public void test() throws CloneNotSupportedException {
        clone();
    }*/
}